# !/usr/bin/python3
# -*- coding: utf-8 -*-
# @Time    : 2020/12/12 22:04
# @Author  : darknight
# @File    : main.py
# @Software: PyCharm
"""
音乐爬虫
"""
from concurrent.futures import ThreadPoolExecutor, wait, as_completed, ALL_COMPLETED

from importlib import import_module
from threading import Thread

from settings import settings


class MusicThread(Thread):

    def __init__(self, func, **kwargs):
        super(MusicThread, self).__init__()
        self.func = func
        self.kwargs = kwargs

    def run(self):
        self.source, self.result = self.func(**self.kwargs)

    def get_res(self):
        return self.source, self.result


class Music(object):
    SPIDER = {}
    PARSER = {}
    SONGS_LIST_CATEGORY_ID = {}
    TOP_LIST_ID = {}

    def __init__(self):
        for app in settings.SPIDER_APP:
            spider_file = import_module(f'spiderApp.{app}.spider')
            parser_file = import_module(f'spiderApp.{app}.parser')
            spider = spider_file.Spider
            # 爬取数据
            self.SPIDER.update({
                spider.NAME: spider()
            })
            # 解析数据
            self.PARSER.update({
                spider.NAME: parser_file.Parser
            })
            # 分类歌单对应的分类ID
            self.SONGS_LIST_CATEGORY_ID.update({
                spider.NAME: spider.SONGS_LIST_CATEGORY_ID
            })
            # 排行榜对应的ID
            self.TOP_LIST_ID.update({
                spider.NAME: spider.TOP_LIST_ID
            })

    def get_recommend_songs_list(self, source=None):
        """
        获取推荐歌单
        :return:
        """
        res = []
        with ThreadPoolExecutor() as executor:
            # 添加任务 executor.submit(func)
            if source:
                all_tasks = [executor.submit(self.SPIDER[source].get_recommend_songs_list)]
            else:
                all_tasks = [executor.submit(spider.get_recommend_songs_list) for name, spider in
                             self.SPIDER.items()]
            wait(all_tasks, return_when=ALL_COMPLETED)
            for future in as_completed(all_tasks):
                source, result = future.result()
                get_res = self.PARSER[source].parser_recommend_songs_list(source, result)
                res.extend(get_res)
        return res

    def get_recommend_songs(self, source=None):
        """
        获取推荐歌曲
        :return:
        """
        res = []
        with ThreadPoolExecutor() as executor:
            # 添加任务 executor.submit(func)
            if source:
                all_tasks = [executor.submit(self.SPIDER[source].get_recommend_songs)]
            else:
                all_tasks = [executor.submit(spider.get_recommend_songs) for name, spider in
                             self.SPIDER.items()]
            wait(all_tasks, return_when=ALL_COMPLETED)
            for future in as_completed(all_tasks):
                source, result = future.result()
                get_res = self.PARSER[source].parser_recommend_songs(source, result)
                res.extend(get_res)
        return res

    def get_songs_list_by_category(self, categoryId, source=None):
        """
        分类歌单
            语种：华语(1)、欧美(2)、韩语(3)、日语(4)
            风格：流行(5)、纯音乐(5)、摇滚(7)、电子(8)、民谣(9)
        :param categoryId:
        :param source: 歌曲来源 netease  qq  xiami
        :return:
        """
        assert all([categoryId, categoryId in range(1, 10)]), "请传入 categoryId(1-9)"

        res = []
        with ThreadPoolExecutor() as executor:
            # 添加任务 executor.submit(func)
            if source:
                category_id = self.SONGS_LIST_CATEGORY_ID[source][categoryId]
                all_tasks = [executor.submit(self.SPIDER[source].get_songs_list_by_category, category_id)
                             ]
            else:
                all_tasks = []
                for name, spider in self.SPIDER.items():
                    category_id = self.SONGS_LIST_CATEGORY_ID[name][categoryId]
                    all_tasks.append(executor.submit(spider.get_songs_list_by_category, category_id))
            wait(all_tasks, return_when=ALL_COMPLETED)
            for future in as_completed(all_tasks):
                source, result = future.result()
                res.extend(self.PARSER[source].parser_songs_list_by_category(source, result))
        return res

    def get_songs_list_detail(self, listId, source):
        """
        歌单详情
        :param listId:
        :param source:
        :return:
        """
        assert all([listId, source]), "请传入 listId, source"
        source, result = self.SPIDER[source].get_songs_list_detail(list_id=listId)
        return self.PARSER[source].parser_songs_list_detail(source, result)

    def get_song_detail(self, songMid, source):
        """
        歌曲详情
        :param songMid:
        :param source:
        :return:
        """
        assert all([songMid, source]), "请传入 songMid, source"
        source, result = self.SPIDER[source].get_song_detail(song_mid=songMid)
        return self.PARSER[source].parser_song_detail(source, result)

    def get_song_lyric(self, songId, source):
        """
        歌词
        :param songId:
        :param source:
        :return:
        """
        assert all([songId, source]), "请传入 songId, source"
        source, result = self.SPIDER[source].get_song_lyric(song_id=songId)
        return self.PARSER[source].parser_song_lyric(source, result)

    def get_song_play_url(self, songMid, source):
        """
        歌曲播放url
        :param songMid:
        :param source:
        :return:
        """
        assert all([songMid, source]), "请传入 songMid, source"
        source, result = self.SPIDER[source].get_song_play_url(song_mid=songMid)
        return self.PARSER[source].parser_song_play_url(source, result)

    def get_mv_play_url(self, mvId, source):
        """
        歌曲MV
        :param mvId:
        :param source:
        :return:
        """
        assert all([mvId, source]), "请传入 mvId, source"
        source, result = self.SPIDER[source].get_mv_play_url(vid=mvId)
        return self.PARSER[source].parser_mv_play_url(source, result)

    def get_top_list(self, topId, source=None):
        """
        歌曲排行榜
            飙升(1)、新歌(2)、热歌(3)、原创(4)、抖音(5)
        :param topId:
        :param source:
        :return:
        """
        assert all([topId, topId in range(1, 6)]), "请传入 topId(1-5)"
        res = []
        with ThreadPoolExecutor() as executor:
            # 添加任务 executor.submit(func)
            if source:
                all_tasks = [executor.submit(self.SPIDER[source].get_top_list,
                                             top_id=self.TOP_LIST_ID[source][topId])]
            else:
                all_tasks = [
                    executor.submit(spider.get_top_list, top_id=self.TOP_LIST_ID[name][topId])
                    for name, spider in self.SPIDER.items()]

            wait(all_tasks, return_when=ALL_COMPLETED)
            for future in as_completed(all_tasks):
                source, result = future.result()
                res.append(self.PARSER[source].parser_top_list(source, result))
        return res

    def get_search_song(self, kw, source=None):
        """
        搜索歌曲
        :param kw:
        :param source:
        :return:
        """
        assert all([kw]), "请传入 kw"
        res = []
        _thread = []
        for name, source in ({source: self.SPIDER[source]} if source else self.SPIDER).items():
            t = MusicThread(source.get_search_song, kw=kw)
            _thread.append(t)
        for t in _thread:
            t.start()
        for t in _thread:
            t.join()
        for t in _thread:
            source, result = t.get_res()
            res.extend(self.PARSER[source].parser_search_song(source, result))
        return res


if __name__ == '__main__':
    music = Music()
    print('***' * 50)
    # 推荐歌单
    # print(len(music.get_recommend_songs_list()))
    # print(len(music.get_recommend_songs_list('qq')))
    # print(len(music.get_recommend_songs_list('xiami')))
    # print(len(music.get_recommend_songs_list('netease')))
    #
    # 推荐歌曲
    # print(len(music.get_recommend_songs()))
    # print(len(music.get_recommend_songs('qq')))
    # print(len(music.get_recommend_songs('xiami')))
    # print(len(music.get_recommend_songs('netease')))
    #
    # 分类歌单
    # 语种：华语(1)、欧美(2)、韩语(3)、日语(4)
    # 风格：流行(5)、纯音乐(5)、摇滚(7)、电子(8)、民谣(9)
    # print(len(music.get_songs_list_by_category(1)))
    # print(len(music.get_songs_list_by_category(1, 'qq')))
    # print(len(music.get_songs_list_by_category(1, 'xiami')))
    # print(len(music.get_songs_list_by_category(1, 'netease')))
    #
    # # 歌单详情
    # list_id = '2931035154'
    # print(music.get_songs_list_detail(list_id, 'qq').keys())
    # list_id = '48102083'
    # print(music.get_songs_list_detail(list_id, 'xiami').keys())
    # list_id = "5204401228"
    # print(music.get_songs_list_detail(list_id, 'netease').keys())
    #
    # 歌曲详情
    # mid = '000QJ4M13JBut8'
    # print(music.get_song_detail(mid, 'qq'))
    # mid = '1488737309'
    # print(music.get_song_detail(mid, 'netease'))
    # mid = 'mSFWBO804da'
    # print(music.get_song_detail(mid, 'xiami'))
    #
    # 歌词
    # song_id = '284614725'
    # print('%r' % music.get_song_lyric(song_id, 'qq'))
    # print('**' * 50)
    # song_id = '1488737309'
    # print('%r' % music.get_song_lyric(song_id, 'netease'))
    # print('**' * 50)
    # song_id = '1801512872'
    # print('%r' % music.get_song_lyric(song_id, 'xiami'))
    #
    # 播放地址
    # _mid = "000QJ4M13JBut8"
    # print(music.get_song_play_url(_mid, 'qq'))
    # _mid = 1488737309
    # print(music.get_song_play_url(_mid, 'netease'))
    # _mid = "mSFWBO804da"
    # print(music.get_song_play_url(_mid, 'xiami'))
    #
    # MV播放地址
    # vid = 'T0010Rcobut'
    # print(music.get_mv_play_url(vid, 'qq'))
    # print('**' * 50)
    # vid = '10730328'
    # print(music.get_mv_play_url(vid, 'netease'))
    # print('**' * 50)
    # vid = 'K6YCDO'
    # print(music.get_mv_play_url(vid, 'xiami'))
    #
    # 排行榜
    # 飙升(1)、新歌(2)、热歌(3)、原创(4)、抖音(5)
    # top_id = 1
    # print(len(music.get_top_list(top_id)))
    # print(len(music.get_top_list(top_id, "qq")))
    # print(len(music.get_top_list(top_id, "xiami")))
    # print(len(music.get_top_list(top_id, "netease")))
    #
    # 搜索
    # print(len(music.get_search_song('夜曲')))
    # print(len(music.get_search_song('夜曲', "qq")))
    # print(len(music.get_search_song('夜曲', "xiami")))
    # print(len(music.get_search_song('夜曲', "netease")))

    print('***' * 50)
